package com.ruicar.afs.cloud.admin.controller;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruicar.afs.cloud.admin.api.dto.TransferDto;
import com.ruicar.afs.cloud.admin.api.dto.UserSimpleInfoDto;
import com.ruicar.afs.cloud.admin.api.dto.Transfer;
import com.ruicar.afs.cloud.admin.api.enums.ChangeType;
import com.ruicar.afs.cloud.admin.api.event.AfsUserChangeEventTrigger;
import com.ruicar.afs.cloud.admin.api.event.UserChangeEventParam;
import com.ruicar.afs.cloud.admin.enums.SysParamType;
import com.ruicar.afs.cloud.admin.util.PassValidateUtil;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.log.annotation.SysLog;
import com.ruicar.afs.cloud.common.core.query.QueryCondition;
import com.ruicar.afs.cloud.common.core.security.dto.UserInfo;
import com.ruicar.afs.cloud.common.core.security.util.SecurityUtils;
import com.ruicar.afs.cloud.admin.entity.SysDepartment;
import com.ruicar.afs.cloud.admin.entity.SysRole;
import com.ruicar.afs.cloud.admin.entity.SysUser;
import com.ruicar.afs.cloud.admin.entity.SysUserRole;
import com.ruicar.afs.cloud.admin.service.SysDepartmentService;
import com.ruicar.afs.cloud.admin.service.SysRoleService;
import com.ruicar.afs.cloud.admin.service.SysUserRoleService;
import com.ruicar.afs.cloud.admin.service.SysUserService;
import com.ruicar.afs.cloud.admin.condition.UserCondition;
import com.ruicar.afs.cloud.common.core.constant.CommonConstants;
import com.ruicar.afs.cloud.common.core.util.IResponse;
import com.ruicar.afs.cloud.common.core.util.RsaUtils;
import com.ruicar.afs.cloud.common.event.AfsEventHelper;
import com.ruicar.afs.cloud.common.event.EventType;
import com.ruicar.afs.cloud.components.datadicsync.SysParamHelper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Fzero
 * @date 2019-01-24
 */
@RestController
@AllArgsConstructor
@RequestMapping("/user")
@Api(value = "user", description = "用户管理模块")
public class UserController {
	private final SysUserService userService;

	private final SysDepartmentService departmentService;

	private final SysRoleService sysRoleService;

	private final SysUserRoleService userRoleService;

	/**
	 * 获取当前用户全部信息
	 * 登录后获取登录用户信息
	 * @return 用户信息
	 */
	@GetMapping(value = {"/info"})
	public IResponse info() {
		String username = SecurityUtils.getUser().getUsername();
		SysUser user = userService.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username));
		if (user == null) {
			return new IResponse<>(null, "获取当前用户信息失败");
		}
		UserInfo userInfo = userService.findUserInfo(user);
		userInfo.getSysUser().setPassword("");
		userInfo.setLoginLogDto(null);
		userInfo.setDataScope(null);
		return new IResponse<>(userInfo);
	}

	/**
	 * 获取指定用户全部信息
	 * 登录时用
	 * @return 用户信息
	 */
	@GetMapping("/info/{username}")
	public IResponse innerInfo(@PathVariable String username) {
		SysUser user = userService.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username));
		if (user == null) {
			return new IResponse<>(null, String.format("用户信息为空 %s", username));
		}
		return new IResponse<>(userService.findUserInfo(user));
	}

	@RequestMapping(value = "/unlock", method = RequestMethod.POST)
	@ApiOperation(value = "解锁验证密码")
	public IResponse<Boolean> unLock(@RequestBody UserCondition userCondition) {
		userCondition.setPassword(RsaUtils.getInstance().decryptByPrivateKeyToString(userCondition.getPassword()));
		if (!userService.validatePassWord(userCondition.getPassword())) {
			return IResponse.fail("密码不正确").setCode(CommonConstants.FAIL);
		}
		return IResponse.success(RsaUtils.getInstance().decryptByPrivateKeyToString(userCondition.getUnLockKey()));
	}

	/**
	 * @param userCondition
	 * @return
	 */
	@RequestMapping(value = "/editmember", method = RequestMethod.POST)
	@ApiOperation(value = "修改用户资料", notes = "需要通过id获取原用户信息")
	@CacheEvict(value = CommonConstants.USER_CACHE_KEY_PREFIX, key = "#userCondition.username")
	@SysLog("修改用户资料")
	@Transactional(rollbackFor = Exception.class)
	public IResponse<Boolean> edit(@RequestBody UserCondition userCondition) {

		SysUser old = userService.getById(userCondition.getUserId());

		// 若修改了手机和邮箱判断是否唯一
		if (!StringUtils.equals(old.getPhone(),userCondition.getPhone())
				&& userService.list(Wrappers.<SysUser>query().lambda().eq(SysUser::getPhone, userCondition.getPhone())).size() > 0) {
			return IResponse.fail("该手机号已绑定其他账户");
		}
		if (!StringUtils.equals(old.getUserEmail(),userCondition.getUserEmail())
				&& userService.list(Wrappers.<SysUser>query().lambda().eq(SysUser::getUserEmail, userCondition.getUserEmail())).size() > 0) {
			return IResponse.fail("该邮箱已绑定其他账户");
		}
		userCondition.setUsername(old.getUsername());
		userCondition.setPassword(old.getPassword());
		if (!userService.updateById(userCondition)) {
			return IResponse.fail("修改失败");
		}
		//删除该用户角色
		userRoleService.deleteByUserId(userCondition.getUserId());
		if (userCondition.getRoleIds() != null && userCondition.getRoleIds().length > 0) {
			//新角色
			for (Long roleId : userCondition.getRoleIds()) {
				SysUserRole ur = new SysUserRole();
				ur.setRoleId(roleId);
				ur.setUserId(userCondition.getUserId());
				userRoleService.save(ur);
			}
		}
		UserChangeEventParam userChangeEventParam = new UserChangeEventParam();
		userChangeEventParam.setChangeType(ChangeType.MODIFY);
		userChangeEventParam.setUserSimpleInfoLists(userService.querySimpleInfosByNames(Arrays.asList(userCondition.getUsername())));
		AfsEventHelper.publishEvent(EventType.DURABLE, AfsUserChangeEventTrigger.class,userChangeEventParam,true);
		return IResponse.success("修改成功");
	}

	/**
	 * @param userCondition
	 * @return
	 */
	@RequestMapping(value = "/modifyPass", method = RequestMethod.POST)
	@ApiOperation(value = "修改自己密码")
	@SysLog("修改自己密码")
	@Transactional(rollbackFor = Exception.class)
	public IResponse<Boolean> modifyPass(@RequestBody UserCondition userCondition) {
		userCondition.setPassword(RsaUtils.getInstance().decryptByPrivateKeyToString(userCondition.getPassword()));
		userCondition.setNewPass(RsaUtils.getInstance().decryptByPrivateKeyToString(userCondition.getNewPass()));
		PassValidateUtil.validatePass(
				SysParamHelper.getString(AfsEnumUtil.key(SysParamType.PASSWORD_BASE_RULE),"0")
				,
				SysParamHelper.getLong(AfsEnumUtil.key(SysParamType.PASSWORD_MIN_LENGTH),6L)
				,
				SysParamHelper.getLong(AfsEnumUtil.key(SysParamType.PASSWORD_MAX_LENGTH),12L)
				,userCondition.getNewPass());
		if (!userService.validatePassWord(userCondition.getPassword())) {
			return IResponse.fail("旧密码不正确");
		}
		if (userService.modifyPass(userCondition, SecurityUtils.getUser())) {
			return IResponse.success(true).setMsg("修改密码成功");
		} else {
			return IResponse.fail("修改密码失败");
		}
	}

	@RequestMapping(value = "/getByCondition", method = RequestMethod.GET)
	@ApiOperation(value = "多条件分页获取用户列表")
	public IResponse<IPage<SysUser>> getByCondition(@ModelAttribute UserCondition user) {
		IPage<SysUser> userList = userService.page(new Page(user.getPageNumber(), user.getPageSize())
				, Wrappers.<SysUser>query().lambda()
						.eq(user.getDeptId()!=null, SysUser::getDeptId, user.getDeptId())
						.eq(StringUtils.isNotEmpty(user.getLockFlag()), SysUser::getLockFlag, user.getLockFlag())
						.eq(StringUtils.isNotEmpty(user.getUsername()), SysUser::getUsername, user.getUsername())
						.eq(StringUtils.isNotEmpty(user.getPhone()), SysUser::getPhone, user.getPhone())
						.eq(StringUtils.isNotEmpty(user.getUserEmail()), SysUser::getUserEmail, user.getUserEmail())
						.ge(StringUtils.isNotEmpty(user.getStartDate()), SysUser::getCreateTime, StringUtils.isEmpty(user.getStartDate())?(null):(DateUtil.parse(StrUtil.concat(true,user.getStartDate()," 00:00:00"), DatePattern.NORM_DATETIME_PATTERN)))
						.le(StringUtils.isNotEmpty(user.getEndDate()), SysUser::getCreateTime, StringUtils.isEmpty(user.getEndDate())?null:(DateUtil.parse(StrUtil.concat(true,user.getEndDate()," 23:59:59"), DatePattern.NORM_DATETIME_PATTERN))));
		for (SysUser u : userList.getRecords()) {
			// 关联部门
			if (u.getDeptId()!=null) {
				SysDepartment department = departmentService.getById(u.getDeptId());
				u.setDepartmentTitle(department.getTitle());
			}
			// 关联角色
			List<SysRole> list = sysRoleService.findRolesByUserId(u.getUserId());
			u.setRoles(list);
			u.setPassword(null);
		}
		return IResponse.success(userList);
	}


	@RequestMapping(value = "/getByDepartmentId/{departmentId}", method = RequestMethod.GET)
	@ApiOperation(value = "根据部门号获取用户")
	public IResponse<List<SysUser>> getByCondition(@PathVariable String departmentId) {

		List<SysUser> list = userService.list(Wrappers.<SysUser>query().lambda().eq(SysUser::getDeptId, departmentId));
		list.forEach(u -> {
			u.setPassword(null);
		});
		return new IResponse<List<SysUser>>().setData(list);
	}

	@RequestMapping(value = "/getAll", method = RequestMethod.GET)
	@ApiOperation(value = "获取全部用户数据")
	public IResponse<List<SysUser>> getByCondition() {

		List<SysUser> list = userService.list();
		for (SysUser u : list) {
			// 关联部门
			if (u.getDeptId()!=null) {
				SysDepartment department = departmentService.getById(u.getDeptId());
				u.setDepartmentTitle(department.getTitle());
			}
			u.setPassword(null);
		}
		return new IResponse<List<SysUser>>().setData(list);
	}

	@RequestMapping(value = "/addmember", method = RequestMethod.POST)
	@ApiOperation(value = "添加用户")
	@SysLog("添加用户")
	@Transactional
	public IResponse<Boolean> adduser(@RequestBody UserCondition u) {

		if (StrUtil.isBlank(u.getUsername()) || StrUtil.isBlank(u.getPassword())) {
			return IResponse.fail("用户名或密码为空");
		}

		if (
				userService.list(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, u.getUsername())
						.or().eq(SysUser::getPhone, u.getPhone())
						.or().eq(SysUser::getUserEmail, u.getUserEmail())
				).size() > 0) {
			return IResponse.fail("该用户名，邮箱或手机号重复");
		}

		PassValidateUtil.validatePass(
				SysParamHelper.getString(AfsEnumUtil.key(SysParamType.PASSWORD_BASE_RULE),"0")
				,
				SysParamHelper.getLong(AfsEnumUtil.key(SysParamType.PASSWORD_MIN_LENGTH),6L)
				,
				SysParamHelper.getLong(AfsEnumUtil.key(SysParamType.PASSWORD_MAX_LENGTH),12L)
				,u.getPassword());
		u.setPassword(SysUserService.ENCODER.encode(u.getPassword()));
		//清除租户id，由插件自动添加
		u.setTenantId(null);
		if (!userService.save(u)) {
			return IResponse.fail("添加失败");
		}
		if (u.getRoleIds() != null && u.getRoleIds().length > 0) {
			//添加角色
			for (Long roleId : u.getRoleIds()) {
				SysUserRole ur = new SysUserRole();
				ur.setUserId(u.getUserId());
				ur.setRoleId(roleId);
				userRoleService.save(ur);
			}
		}
		return new IResponse().setData(true);
	}

	@RequestMapping(value = "/disable/{userId}", method = RequestMethod.POST)
	@ApiOperation(value = "禁用用户")
	@Transactional
	@SysLog("禁用用户")
	public IResponse<Boolean> disable(@ApiParam("用户唯一id标识") @PathVariable String userId) {
		SysUser user = userService.getById(userId);
		if (user == null) {
			return IResponse.fail("通过userId获取用户失败");
		}
		user.setLockFlag(CommonConstants.STATUS_LOCK);
		userService.updateUser(user);
		UserChangeEventParam userChangeEventParam = new UserChangeEventParam();
		userChangeEventParam.setChangeType(ChangeType.DISABLE);
		userChangeEventParam.setUserSimpleInfoLists(userService.querySimpleInfosByNames(Arrays.asList(user.getUsername())));
		AfsEventHelper.publishEvent(EventType.DURABLE, AfsUserChangeEventTrigger.class,userChangeEventParam,true);
		return new IResponse().setData(true);
	}

	@RequestMapping(value = "/enable/{userId}", method = RequestMethod.POST)
	@ApiOperation(value = "后台启用用户")
	@Transactional
	@SysLog("禁用用户")
	public IResponse<Object> enable(@ApiParam("用户唯一id标识") @PathVariable String userId) {
		SysUser user = userService.getById(userId);
		if (user == null) {
			return IResponse.fail("通过userId获取用户失败");
		}
		user.setLockFlag(CommonConstants.STATUS_NORMAL);
		userService.updateUser(user);
		UserChangeEventParam userChangeEventParam = new UserChangeEventParam();
		userChangeEventParam.setChangeType(ChangeType.ENABLE);
		userChangeEventParam.setUserSimpleInfoLists(userService.querySimpleInfosByNames(Arrays.asList(user.getUsername())));
		AfsEventHelper.publishEvent(EventType.DURABLE, AfsUserChangeEventTrigger.class,userChangeEventParam,true);
		return new IResponse().setData(true);
	}

	@RequestMapping(value = "/delByIds/{ids}", method = RequestMethod.DELETE)
	@ApiOperation(value = "批量通过ids删除")
	@SysLog("批量通过ids删除")
	public IResponse<Boolean> delAllByIds(@PathVariable String[] ids) {
		List<Long> userIds = Arrays.stream(ids).map(Long::parseLong).collect(Collectors.toList());
		List<String> userNames = userService.listByIds(userIds).stream().map(SysUser::getUsername).collect(Collectors.toList());
		userService.deleteByUserIds(userIds);
		UserChangeEventParam userChangeEventParam = new UserChangeEventParam();
		userChangeEventParam.setChangeType(ChangeType.DELETE);

		userChangeEventParam.setUserSimpleInfoLists(userService.querySimpleInfosByNames(userNames));
		AfsEventHelper.publishEvent(EventType.DURABLE, AfsUserChangeEventTrigger.class,userChangeEventParam,true);
		return new IResponse<Boolean>().setMsg("批量通过id删除数据成功");
	}

	@RequestMapping(value = "/resetPassWithDefault/{id}", method = RequestMethod.POST)
	@ApiOperation(value = "重置用户密码")
	@SysLog("通过id重置用户密码")
	@PreAuthorize("@pms.hasPermission('user_pass_reset')")
	public IResponse<Boolean> resetPassWithDefault(@PathVariable Long id) {
		SysUser user = userService.getById(id);
		if (user == null) {
			return IResponse.fail("用户密码重置失败");
		}
		user.setPassword(SysUserService.ENCODER.encode(CommonConstants.DEFAULT_PASS));
		user.setLastLoginFailTime(System.currentTimeMillis());
		user.setLastPassChangeTime(0L);
		user.setLockFlag(CommonConstants.STATUS_NORMAL);
		user.setPassErrorCount(0);
		user.setLastPassChangeTime(0L);
		userService.updateUser(user);
		userService.kickOutUser(user);
		return IResponse.success("密码重置成功");
	}



	/**
	 * 用户登录失败写信息
	 * @return 用户信息
	 */
	@GetMapping("/loginFail/{username}")
	public IResponse loginFail(@PathVariable String username) {
		userService.loginFail(username);
		return new IResponse<>(Boolean.TRUE);
	}

	/**
	 * 重置用户登录失败信息
	 * @return 用户信息
	 */
	@PostMapping("/resetFaiCount/{id}")
	public IResponse resetFaiCount(@PathVariable Long id) {
		SysUser user = 	userService.getById(id);
		userService.resetLoginFailTime(user);
		return new IResponse<>(Boolean.TRUE);
	}
	/**
	 * 重置用户登录失败信息
	 * @return 用户信息
	 */
	@GetMapping("/resetLoginFail/{username}")
	public IResponse resetLoginFail(@PathVariable String username) {
		userService.resetLoginFailTime(username);
		return new IResponse<>(Boolean.TRUE);
	}

	@PostMapping("/getSimpleInfoByUserLoginNames")
	public IResponse<List<UserSimpleInfoDto>> getUsersInfo(@RequestBody List<String> usernames){
		if(usernames==null||usernames.size()==0){
			return IResponse.success(new ArrayList<>());
		}else{
			return IResponse.success(userService.querySimpleInfosByNames(usernames));
		}
	}

	@PostMapping("/getSimpleUserListByRoleCode/{roleCode}")
	public IResponse<List<UserSimpleInfoDto>> getSimpleUserListByRoleCode(@PathVariable String roleCode){
		if(StringUtils.isEmpty(roleCode)){
			return IResponse.success(new ArrayList<>());
		}else{
			return IResponse.success(userService.getSimpleUserListByRoleCode(roleCode));
		}
	}


	@PostMapping("/pageQuerySimpleUserInfo")
	public IResponse<Page<UserSimpleInfoDto>> pageQuerySimpleUserInfo(@RequestBody QueryCondition<UserSimpleInfoDto> queryCondition){
		return IResponse.success(userService.pageQuerySimpleUserInfo(queryCondition));
	}
	@GetMapping("/userTransferList/{roleId}")
	public IResponse<TransferDto> userTransFerData(@PathVariable Long roleId){
		SysRole sysRole = sysRoleService.getById(roleId);
		TransferDto transferDto =  new TransferDto();
		List<Transfer> transferList =  userService.list().stream().filter(sysUser -> !sysUser.getUserId().equals(SecurityUtils.getUser().getId())).map(sysUser -> {
			Transfer transfer = new Transfer();
			transfer.setKey(Long.valueOf(sysUser.getUserId()));
			transfer.setDisabled(CommonConstants.STATUS_LOCK.equalsIgnoreCase(sysUser.getLockFlag()));
			transfer.setLabel(MessageFormat.format("{0}-{1}",sysUser.getUsername(),sysUser.getUserRealName()));
			return  transfer;
		}).collect(Collectors.toList());
		transferDto.setTransferList(transferList);
		if(sysRole!=null){
			transferDto.setKeys(userService.getSimpleUserListByRoleCode(sysRole.getRoleCode()).stream().map(UserSimpleInfoDto::getUserId).filter(userId-> userId!=SecurityUtils.getUser().getId()).map(Object::toString).collect(Collectors.toList()));
		}else {
			transferDto.setKeys(new ArrayList<>());
		}
		return IResponse.success(transferDto);
	}
}
